#ifndef FFPLAY_STATER_H
#define FFPLAY_STATER_H
#define FRAME_QUEUE_SIZE 15
#include <inttypes.h>
#include <math.h>
#include <limits.h>
#include <signal.h>
#include <stdint.h>
extern "C" {
#include "libavutil/avstring.h"
#include "libavutil/eval.h"
#include "libavutil/mathematics.h"
#include "libavutil/pixdesc.h"
#include "libavutil/imgutils.h"
#include "libavutil/dict.h"
#include "libavutil/parseutils.h"
#include "libavutil/samplefmt.h"
#include "libavutil/avassert.h"
#include "libavutil/time.h"
#include "libavformat/avformat.h"
#include "libavdevice/avdevice.h"
#include "libswscale/swscale.h"
#include "libavutil/opt.h"
#include "libavcodec/avfft.h"
#include "libswresample/swresample.h"
}
#include <SDL.h>
#include <SDL_thread.h>
#include <assert.h>
#include "errnoc.h"
#include <iostream>

#define VIDEO_PICTURE_QUEUE_SIZE	3       // 图像帧缓存数量
#define VIDEO_PICTURE_QUEUE_SIZE_MIN        (3)
#define VIDEO_PICTURE_QUEUE_SIZE_MAX        (16)
#define VIDEO_PICTURE_QUEUE_SIZE_DEFAULT    (VIDEO_PICTURE_QUEUE_SIZE_MIN)
#define SUBPICTURE_QUEUE_SIZE		16      // 字幕帧缓存数量
#define SAMPLE_QUEUE_SIZE           9       // 采样帧缓存数量
#define FRAME_QUEUE_SIZE FFMAX(SAMPLE_QUEUE_SIZE, FFMAX(VIDEO_PICTURE_QUEUE_SIZE, SUBPICTURE_QUEUE_SIZE))
extern int vidindex;


enum RET_CODE
{
    RET_ERR_UNKNOWN = -2,                   // 未知错误
    RET_FAIL = -1,							// 失败
    RET_OK	= 0,							// 正常
    RET_ERR_OPEN_FILE,						// 打开文件失败
    RET_ERR_NOT_SUPPORT,					// 不支持
    RET_ERR_OUTOFMEMORY,					// 没有内存
    RET_ERR_STACKOVERFLOW,					// 溢出
    RET_ERR_NULLREFERENCE,					// 空参考
    RET_ERR_ARGUMENTOUTOFRANGE,				//
    RET_ERR_PARAMISMATCH,					//
    RET_ERR_MISMATCH_CODE,                  // 没有匹配的编解码器
    RET_ERR_EAGAIN,
    RET_ERR_EOF
};

typedef struct AudioParams {
    int			freq;                   // 采样率
    int			channels;               // 通道数
    int64_t		channel_layout;         // 通道布局，比如2.1声道，5.1声道等
    enum AVSampleFormat	fmt;            // 音频采样格式，比如AV_SAMPLE_FMT_S16表示为有符号16bit深度，交错排列模式。
    int			frame_size;             // 一个采样单元占用的字节数（比如2通道时，则左右通道各采样一次合成一个采样单元）
    int			bytes_per_sec;          // 一秒时间的字节数，比如采样率48Khz，2 channel，16bit，则一秒48000*2*16/8=192000
} AudioParams;

struct Buff{
     uint8_t *buff;
     unsigned int buffsize;
    // int buffindex =0;
     Buff(uint8_t *d = nullptr, int s = 0) :  buff(d), buffsize(s) {}
} ;

typedef struct AVPacketList{
    AVPacket packet;
    AVPacketList *next;
    int serial;
}AVPacketList;

typedef struct PakcetQueue{
    AVPacketList	*first_pkt, *last_pkt;  // 队首，队尾指针
    int		nb_packets;   // 包数量，也就是队列元素数量
    int		size;         // 队列所有元素的数据大小总和
    int64_t		duration; // 队列所有元素的数据播放持续时间
    int		abort_request; // 用户退出请求标志
    int		serial;         // 播放序列号，和MyAVPacketList的serial作用相同，但改变的时序稍微有点不同
    SDL_mutex	*mutex;     // 用于维持PacketQueue的多线程安全(SDL_mutex可以按pthread_mutex_t理解）
    SDL_cond	*cond;      // 用于读、写线程相互通知(SDL_cond可以按pthread_cond_t理解)
    //AVPacket flush_pkt;
} PacketQueue;
typedef struct Frame {
    AVFrame		*frame;         // 指向数据帧
    double		pts;            // 时间戳，单位为秒
    double		duration;       // 该帧持续时间，单位为秒
    int     pos;                // 偏移量
    int		serial;
    int		width;              // 图像宽度
    int		height;             // 图像高读
    int		format;             // 对于图像为(enum AVPixelFormat)
}Frame;
//AV_PIX_FMT_YUV420P
/* 这是一个循环队列，windex是指其中的首元素，rindex是指其中的尾部元素. */
typedef struct FrameQueue {
    Frame	queue[FRAME_QUEUE_SIZE];        // FRAME_QUEUE_SIZE  最大size, 数字太大时会占用大量的内存，需要注意该值的设置
    int		rindex;                         // 读索引。待播放时读取此帧进行播放，播放后此帧成为上一帧
    int		windex;                         // 写索引
    int     shown = 0 ;                     // 是否正在输出

    int		size;                           // 当前总帧数
    int		max_size;                       // 可存储最大帧数
    SDL_mutex	*mutex;                     // 互斥量
    SDL_cond	*cond;                      // 条件变量
    PacketQueue	*pktq;                      // 数据包缓冲队列
}FrameQueue;
//刷新包
static AVPacket flush_pkt;

int frame_queue_init(PakcetQueue *q,FrameQueue *frm_queue, int maxsize );
int frame_queue_destroy(FrameQueue *q);
int frame_queue_flush(FrameQueue *q);
int frame_queue_write(FrameQueue *q,AVFrame *frame);
int frame_queue_get_wirtable(FrameQueue *q,Frame **frame);
int frame_queue_next_wirte(FrameQueue *q);
int frame_queue_get_readable(FrameQueue *q,Frame **frame);
int frame_queue_get_last_readable(FrameQueue *q,Frame **frame);
Frame* frame_queue_get(FrameQueue *q);
Frame* frame_queue_get_last(FrameQueue *q);
Frame* frame_queue_get_next(FrameQueue *q);
int frame_queue_next_read(FrameQueue *q);
void frame_queue_free(Frame *f);
int frame_queue_nb_remaining(FrameQueue *q);

int packet_queue_init(PakcetQueue *q);
int pakcet_queue_destroy(PakcetQueue *q);
int pakcet_queue_flush(PakcetQueue *q);
int packet_queue_start(PakcetQueue *q);
int packet_queue_put(PakcetQueue *q,AVPacket *pkt);
int packet_queue_put_nullpkt(PakcetQueue *q,int stream_index);
int packet_queue_put_l(PakcetQueue *q,AVPacket *pkt);
int packet_queue_get(PakcetQueue *q,AVPacket *pkt,int block,int *pkt_serial);

double get_duration(Frame *vp ,Frame *lastvp);

#endif // FFPLAY_STATER_H
